             package com.java.diagnostics.visualizer.recommender.balanced;
             
             import com.java.diagnostics.visualizer.data.AggregateData;
             import com.java.diagnostics.visualizer.data.DataPoint;
             import com.java.diagnostics.visualizer.data.StructuredData;
             import com.java.diagnostics.visualizer.data.TupleData;
             import com.java.diagnostics.visualizer.parser.vgc.constants.VGCAxes;
             import com.java.diagnostics.visualizer.parser.vgc.constants.VGCGCReasons;
             import com.java.diagnostics.visualizer.recommender.Recommendation;
             import com.java.diagnostics.visualizer.recommender.RecommendationBase;
             import com.java.diagnostics.visualizer.recommender.util.RecommendationLabels;
             import java.text.MessageFormat;
             import java.util.Map;
             
             public class LookForLongGlobalsAfterAF
               extends RecommendationBase
               implements Recommendation
             {
               private long maxHeap = 0L;
               
               public void recommend(AggregateData data)
               {
                 Object gcMode = getGCMode(data);
                 
                 if ("balanced".equals(gcMode))
                 {
                   TupleData reasonRecord = data
                     .getTupleData("VGCLabels.gc.reasons");
                   
                   TupleData pauseTime = data
                     .getTupleData("VGCLabels.pause.times.without.exclusive.access");
                   
                   if ((reasonRecord != null) && (pauseTime != null)) {
                     DataPoint[] reasonPoints = reasonRecord.getDataPoints();
                     double averagePauseTime = pauseTime.getRawMeanY();
                     int globalPauses = 0;int longPauses = 0;
                     double globalTotal = 0.0D;
                     
                     for (DataPoint reason : reasonPoints) {
                       if (reason.getY(VGCAxes.REASONCODE) == VGCGCReasons.AF_INT) {
                         globalPauses++;
                         double globalPauseTime = pauseTime.getDataPoint(
                           reason.getSequenceUID()).getRawY();
                         
                         if ((globalPauseTime > 2.0D * averagePauseTime) && 
                           (heapIsFullyExpanded(data, reason))) {
                           longPauses++;
                           globalTotal += globalPauseTime;
                         }
                       }
                     }
                     if (longPauses > 0) {
                       double meanLongGlobal = globalTotal / longPauses;
                       long percent = Math.round(meanLongGlobal / averagePauseTime * 
                         100.0D);
                       
                       addWarning(data, MessageFormat.format(
                         RecommendationLabels.LONG_GLOBALS_WARNING, 
                         new Object[] { Integer.valueOf(globalPauses), Long.valueOf(percent) }));
                     }
                   }
                 }
               }
               
               private boolean heapIsFullyExpanded(AggregateData data, DataPoint point) {
                 TupleData heapSize = data.getTupleData("VGCLabels.flat.heap.size");
                 if (heapSize != null) {
                   double currentSize = heapSize.getDataPoint(point.getSequenceUID())
                     .getRawY();
                   if (this.maxHeap == 0L) {
                     StructuredData attributes = data
                       .getStructuredData("VGCLabels.gc.attributes");
                     
                     if (attributes != null) {
                       String regionCount = (String)attributes.getContents().get(
                         "regionCount");
                       
                       String regionSize = (String)attributes.getContents().get(
                         "regionSize");
                       
                       this.maxHeap = (new Long(regionCount).longValue() * new Long(regionSize).longValue());
                     }
                   }
                   return this.maxHeap == currentSize;
                 }
                 return false;
               }
             }


